package com.dragon.client.config.aop;


import cn.hutool.core.date.DateUtil;
import com.dragon.client.config.annotation.Log;
import com.dragon.common.util.JwtUtil;
import com.dragon.logical.service.auth.AdminService;
import com.dragon.logical.service.auth.IOperationLogService;
import com.dragon.repository.entity.OperationLog;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Arrays;

@Aspect
@Component
@Slf4j
public class OperationLogAop {

    @Autowired
    IOperationLogService operationLogService;

    @Autowired
    AdminService adminService;


    @Pointcut("@annotation(com.dragon.client.config.annotation.Log)")
    public void operationLogPointCut(){

    }



    @AfterReturning(pointcut = "operationLogPointCut()")
    public void doAfterReturning(JoinPoint joinPoint){
        handleLog(joinPoint);
    }


    public void handleLog(JoinPoint joinPoint){

        Log logs = getAnnotation(joinPoint);
        RequestAttributes ra = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes sra = (ServletRequestAttributes) ra;
        assert sra != null;
        HttpServletRequest request = sra.getRequest();
        OperationLog operationLog = new OperationLog();
        operationLog.setIpAddress(request.getRemoteAddr());
        operationLog.setArg(Arrays.toString(joinPoint.getArgs()));
        operationLog.setActionCode(request.getMethod());

        //如果是登录，则查询当前参数中的账号信息
        if(request.getRequestURI().toString().equals("/auth/login")||request.getRequestURI().toString().equals("/client/auth/login")||request.getRequestURI().toString().equals("/appLogin/login")){
            operationLog.setAdminId(adminService.selectAdminIdByAccountOrPhone(joinPoint.getArgs()));
        } else {
            operationLog.setAdminId(Integer.valueOf(JwtUtil.getAdminId(request)));
        }

        operationLog.setUri(request.getRequestURI().toString());

        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();
        ApiOperation apiOperation = method.getAnnotation(ApiOperation.class);
        operationLog.setModelCode(joinPoint.getTarget().getClass().getName());
        operationLog.setName(apiOperation.value());
        operationLog.setActionCode(method.getName());

        Api api = joinPoint.getTarget().getClass().getAnnotation(Api.class);
        String strings = String.join("", api.tags());
        operationLog.setModelName(strings.toString());
        operationLog.setOperationTime(DateUtil.date());

        //添加日志
        operationLogService.addLogs(operationLog);
    }

    /**
     * 方法抛出异常时执行
     */
    @AfterThrowing(pointcut = "operationLogPointCut()", throwing = "exception")
    public void doAfterThrowing(JoinPoint joinPoint, Exception exception) {
        try {

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 是否存在注解，如果存在就获取，不存在则返回null
     * @param joinPoint
     * @return
     */
    private Log getAnnotation(JoinPoint joinPoint) {
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();
        if (method != null) {
            return method.getAnnotation(Log.class);
        }
        return null;
    }
}
